home *** CD-ROM | disk | FTP | other *** search
- /* SCCS Id: @(#)amisnd.c 3.1 92/11/28 */
- /* Copyright (c) 1992, 1993 by Gregg Wonderly */
- /* NetHack may be freely redistributed. See license for details. */
-
- /*
- * This file contains music playing code.
- *
- * If we were REALLY determined, we would make the sound play
- * asynchronously, but I'll save that one for a rainy day...
- */
-
- #include "hack.h"
-
- #undef red
- #undef blue
- #undef green
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <exec/io.h>
- #include <devices/audio.h>
- #include <dos/dos.h>
- #include <dos/dosextens.h>
- #include <graphics/gfxbase.h>
-
- #include <clib/exec_protos.h>
- #include <clib/alib_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/graphics_protos.h>
-
- #include <stdio.h>
- #include <stdlib.h>
-
- #define AMII_AVERAGE_VOLUME 60
-
- int amii_volume = AMII_AVERAGE_VOLUME;
-
- typedef struct VHDR
- {
- char name[4];
- long len;
- unsigned long oneshot, repeat, samples;
- UWORD freq;
- UBYTE n_octaves, compress;
- LONG volume;
- } VHDR;
-
- typedef struct IFFHEAD
- {
- char FORM[4];
- long flen;
- char _8SVX[4];
- VHDR vhdr;
- char NAME[4];
- long namelen;
- } IFFHEAD;
-
- extern struct GfxBase *GfxBase;
-
- UBYTE whichannel[] = { 1, 2, 4, 8 };
- void makesound( char *, char *, int vol);
- void amii_speaker( struct obj *instr, char *melody, int vol );
-
- /* A major scale in indexs to freqtab... */
- int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 };
-
- /* Frequencies for a scale starting at one octave below 'middle C' */
- long freqtab[] = {
- 220, /*A */
- 233, /*Bb*/
- 246, /*B */
- 261, /*C */
- 277, /*Db*/
- 293, /*D */
- 311, /*Eb*/
- 329, /*E */
- 349, /*F */
- 370, /*Gb*/
- 392, /*G */
- 415, /*Ab*/
- 440, /*A */
- };
-
- #ifdef TESTING
- main( argc, argv )
- int argc;
- char **argv;
- {
- makesound( "wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60 );
- makesound( "wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60 );
- makesound( "wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60 );
- makesound( "wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60 );
- makesound( "wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 );
- }
- #else
- void
- amii_speaker( struct obj *instr, char *melody, int vol )
- {
- int typ = instr->otyp;
- const char * actualn = OBJ_NAME( objects[typ] ) ;
-
- /* Make volume be relative to users volume level, with 60 being the
- * average level that will be passed to us.
- */
- vol = vol * amii_volume / AMII_AVERAGE_VOLUME;
-
- makesound( actualn, melody, vol );
- }
- #endif
-
- void
- makesound ( char *actualn , char * melody, int vol )
- {
- char *t;
- int c, cycles, dot, dlay;
- FILE *fp = 0;
- IFFHEAD iffhead;
- struct IOAudio *AudioIO = 0;
- struct MsgPort *AudioMP = 0;
- struct Message *AudioMSG = 0;
- ULONG device = -1;
- BYTE *waveptr = 0;
- LONG frequency=440, duration=1, clock, samp, samples, samcyc=1;
- unsigned char name [ 100 ] ;
-
- if ( flags.silent )
- return;
-
- if( GfxBase->DisplayFlags & PAL )
- clock = 3546895;
- else
- clock = 3579545;
-
- /*
- * Is this a known instrument ?
- *
- */
- sprintf ( name, "NetHack:sounds/%s", actualn ) ;
- for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) )
- *t = '_';
- if( (fp = fopen( name, "r" )) == NULL )
- {
- if((fp=fopen(&name[15],"r"))==NULL){
- perror( name );
- return;
- }
- }
-
- AudioIO = (struct IOAudio *)
- AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR );
- if( AudioIO == 0 )
- goto killaudio;
-
- AudioMP = CreatePort( NULL, 0 );
- if( AudioMP == 0 )
- goto killaudio;
-
- AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
- AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
- AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
- AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
- AudioIO->ioa_AllocKey = 0;
- AudioIO->ioa_Data = whichannel;
- AudioIO->ioa_Length = sizeof( whichannel );
-
- device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L );
- if( device != 0 )
- goto killaudio;
-
- if( fread( &iffhead, sizeof( iffhead ), 1, fp ) != 1 )
- goto killaudio;
-
- /* This is an even number of bytes long */
- if( fread( name, (iffhead.namelen+1) & ~1, 1, fp ) != 1 )
- goto killaudio;
-
- if( fread( &samples, 4, 1, fp ) != 1 )
- goto killaudio;
-
- if( fread( &samples, 4, 1, fp ) != 1 )
- goto killaudio;
-
- waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC );
- if( !waveptr )
- goto killaudio;
-
- if( fread( waveptr, samples, 1, fp ) != 1 )
- goto killaudio;
-
- while( melody[0] && melody[1] )
- {
- c = *melody++;
- duration = *melody++;
- dot = 0;
- if( *melody == '.' )
- {
- dot = 1;
- ++melody;
- }
- switch( duration )
- {
- case 'w': dlay = 3; duration = 1; cycles = 1; break;
- case 'h': dlay = 3; duration = 2; cycles = 1; break;
- case 'q': dlay = 2; duration = 4; cycles = 1; break;
- case 'e': dlay = 1; duration = 8; cycles = 1; break;
- case 'x': dlay = 0; duration = 16; cycles = 1; break;
- case 't': dlay = 0; duration = 32; cycles = 1; break;
- default: goto killaudio; /* unrecognized duration */
- }
-
- /* Lower case characters are one octave above upper case */
- switch( c )
- {
- case 'a': case 'b': case 'c':
- case 'd': case 'e': case 'f': case 'g':
- c -= 'a' - 7;
- break;
-
- case 'A': case 'B': case 'C':
- case 'D': case 'E': case 'F': case 'G':
- c -= 'A';
- break;
-
- default:
- continue;
- }
-
- samcyc = samples;
-
- /* lowercase start at middle 'C', upper case are one octave below */
- frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]];
-
- /* We can't actually do a dotted whole note unless we add code for a real
- * 8SVX sample which includes sustain sample information to tell us how
- * to hold the note steady... So when duration == 1, ignore 'dot'...
- */
- if( dot && duration > 1 )
- samp = ((samples / duration) * 3) / 2;
- else
- samp = samples / duration;
-
- /* Only use some of the samples based on frequency */
- samp = frequency * samp / 880;
-
- /* The 22khz samples are middle C samples, so adjust the play
- * back frequency accordingly
- */
- frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L;
-
- AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP;
- AudioIO->ioa_Request.io_Command = CMD_WRITE;
- AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
- AudioIO->ioa_Data = (BYTE *)waveptr;
- AudioIO->ioa_Length = samp;
-
- /* The clock rate represents the unity rate, so dividing by
- * the frequency gives us a period ratio...
- */
- /*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, clock/frequency );*/
- AudioIO->ioa_Period = clock/frequency;
- AudioIO->ioa_Volume = vol;
- AudioIO->ioa_Cycles = cycles;
-
- BeginIO( (struct IORequest *)AudioIO );
- WaitPort( AudioMP );
- AudioMSG = GetMsg( AudioMP );
- if( dlay )
- Delay( dlay );
- }
-
- killaudio:
- if( fp ) fclose( fp );
- if( waveptr ) FreeMem( waveptr, samples );
- if( device == 0 ) CloseDevice( (struct IORequest *)AudioIO );
- if( AudioMP ) DeletePort( AudioMP );
- if( AudioIO ) FreeMem( AudioIO, sizeof( *AudioIO ) );
- }
-